/*            Copyright(c) 2006-2008 Dave Sexton           *
 * http://www.codeplex.com/DocProject                      *
 * http://www.codeplex.com/DocProject/Project/License.aspx *
 ***********************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.XPath;
using System.Collections.ObjectModel;

namespace DaveSexton.DocProject.Sandcastle.TopicManagement
{
	public sealed class MRefBuilderConfigApiFilter : MarshalByRefObject
	{
		#region Public Properties
		public bool ApiExposed
		{
			get
			{
				return apiExposed;
			}
			set
			{
				ApiFilterConfigNode.Expose(apiFilter, apiExposed = value);
			}
		}

		public ICollection<NamespaceConfigNode> Namespaces
		{
			get
			{
				return new ReadOnlyCollection<NamespaceConfigNode>(namespaces);
			}
		}

		public NamespaceConfigNode this[string @namespace]
		{
			get
			{
				return namespaces[@namespace];
			}
		}

		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1023:IndexersShouldNotBeMultidimensional")]
		public TypeConfigNode this[string @namespace, string type]
		{
			get
			{
				NamespaceConfigNode node = namespaces[@namespace];

				if (node == null)
					return null;
				else
					return node[type];
			}
		}

		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1023:IndexersShouldNotBeMultidimensional")]
		public MemberConfigNode this[string @namespace, string type, string member]
		{
			get
			{
				NamespaceConfigNode node = namespaces[@namespace];

				if (node == null)
					return null;

				return node[type, member];
			}
		}
		#endregion

		#region Private / Protected
		private readonly ApiFilterConfigNodeCollection<NamespaceConfigNode> namespaces;
		private readonly XPathNavigator apiFilter;
		private bool apiExposed;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="MRefBuilderConfigApiFilter" /> class.
		/// </summary>
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "dduetools")]
		public MRefBuilderConfigApiFilter(IXPathNavigable dduetools)
		{
			apiFilter = dduetools.CreateNavigator();

			if (!apiFilter.MoveToChild("apiFilter", ""))
			{
				apiFilter.AppendChildElement(null, "apiFilter", null, null);
				apiFilter.MoveToChild("apiFilter", "");
			}

			if (!apiFilter.MoveToAttribute("expose", ""))
			{
				apiFilter.CreateAttribute(null, "expose", null, "true");
				apiExposed = true;
			}
			else
			{
				if (!bool.TryParse(apiFilter.Value, out apiExposed))
				{
					apiFilter.SetValue("true");
					apiExposed = true;
				}

				apiFilter.MoveToParent();
			}

			namespaces = new ApiFilterConfigNodeCollection<NamespaceConfigNode>();

			foreach (XPathNavigator node in apiFilter.SelectChildren("namespace", ""))
			{
				// use the internal constructor to create the instance without creating a corresponding xml node, which already exists
				NamespaceConfigNode @namespace = new NamespaceConfigNode(node);

				namespaces.Add(@namespace);

				foreach (XPathNavigator node2 in node.SelectChildren("type", ""))
				{
					// use the internal constructor to create the instance without creating a corresponding xml node, which already exists
					TypeConfigNode type = new TypeConfigNode(@namespace, node2);

					@namespace.AddType(type);

					foreach (XPathNavigator node3 in node2.SelectChildren("member", ""))
					{
						// use the internal constructor to create the instance without creating a corresponding xml node, which already exists
						MemberConfigNode member = new MemberConfigNode(type, node3);

						type.AddMember(member);
					}
				}
			}
		}
		#endregion

		#region Methods
		[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.LinkDemand,
			Flags = System.Security.Permissions.SecurityPermissionFlag.Infrastructure)]
		public override object InitializeLifetimeService()
		{
			return null;
		}

		public void Clear()
		{
			namespaces.Clear();

			if (apiFilter.HasChildren)
			{
				XPathNavigator child = apiFilter.Clone();

				while (child.MoveToChild(XPathNodeType.Element))
					// NOTE: after the child is deleted it points to the parent node automatically (apiFilter element)
					child.DeleteSelf();
			}
		}

		public NamespaceConfigNode AppendNamespaceNode(string @namespace, bool expose)
		{
			// this internal constructor creates the node in the xml document automatically
			NamespaceConfigNode node = new NamespaceConfigNode(apiFilter, @namespace, expose);

			namespaces.Add(node);

			return node;
		}

		public bool IsNamespaceExposed(string @namespace)
		{
			// NOTE: allow null values
			NamespaceConfigNode node = namespaces[@namespace];

			return (node != null) ? node.IsExposed : apiExposed;
		}

		public bool IsTypeExposed(string @namespace, string type)
		{
			// NOTE: allow null values
			NamespaceConfigNode node = namespaces[@namespace];

			if (node == null)
				return apiExposed;

			TypeConfigNode node2 = node[type];

			return (node2 != null) ? node2.IsExposed : node.IsExposed;
		}

		public bool IsMemberExposed(string @namespace, string type, string member)
		{
			// NOTE: allow null values
			NamespaceConfigNode node = namespaces[@namespace];

			if (node == null)
				return apiExposed;

			TypeConfigNode node2 = node[type];

			if (node2 == null)
				return node.IsExposed;

			MemberConfigNode node3 = node2[member];

			return (node3 != null) ? node3.IsExposed : node2.IsExposed;
		}

		public bool HasNamespace(string name)
		{
			return namespaces[name] != null;
		}

		public bool HasType(string @namespace, string type)
		{
			NamespaceConfigNode node = namespaces[@namespace];

			if (node == null)
				return false;
			else
				return node[type] != null;
		}

		public bool HasMember(string @namespace, string type, string member)
		{
			NamespaceConfigNode node = namespaces[@namespace];

			if (node == null)
				return false;
			else
				return node[type, member] != null;
		}
		#endregion
	}
}
